package com.imrookie.gendoc.apiword;


import com.imrookie.gendoc.apiword.template.ApiClassTemplate;
import com.imrookie.gendoc.apiword.template.ApiMethodTemplate;
import com.imrookie.gendoc.apiword.template.ApiTemplate;
import com.imrookie.gendoc.test.TestInterface;
import com.imrookie.wrap.*;
import com.jd.o2o.cart.api.CartNewService;
import freemarker.template.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.*;

/**
 * @author wangjiyu@imdada.cn
 * @create 2018/12/29
 */

public class GenMain {

    private static final Logger logger = LoggerFactory.getLogger(GenMain.class);

    public static void main(String[] args) {
        try {
            gen("C:\\Users\\zhouhuawei\\Desktop\\jsf接口文档2.doc", CartNewService.class);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }

    }

    /**
     * 生成接口文档
     * @param filePath 文件地址
     * @param clazzs 接口类
     * @throws IOException
     * @throws TemplateException
     */

    public static void gen(String filePath, Class... clazzs) throws IOException, TemplateException {
        List<ApiTemplate> list = assembleApiTemplate(clazzs);

        //配置
        Configuration configuration = new Configuration();
        configuration.setClassForTemplateLoading(GenMain.class, "/");//注意路径以斜杠'/'开头

        //获取模板文件
        Template template = configuration.getTemplate("JSF-API-DOC.ftl", "UTF-8");//, "UTF-8"

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("apiList", list);

        File file = new File(filePath);
        if (file.exists()) {
            file.createNewFile();
        }
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(fileOutputStream));
        template.process(map, bufferedWriter);//写入
    }

    /**
     * 装配api模板bean
     * @param clazzs
     * @return
     */

    public static List<ApiTemplate> assembleApiTemplate(Class... clazzs) {
        List<ApiTemplate> res = new ArrayList<ApiTemplate>();
        if (clazzs != null && clazzs.length > 0 ) {
            for (int i=0;i<clazzs.length;i++) {
                Class clazz = clazzs[i];
                ClassWrap classWrap = ClassWrap.getInstance(clazz);//包装类
                ApiTemplate apiTemplate = new ApiTemplate(i+1, classWrap.getWholeClassName());
                if (classWrap.getMethodWraps() == null || classWrap.getMethodWraps().length == 0) {
                    logger.info("类{}没有方法", classWrap.getClassName());
                    continue;
                }
                List<ApiMethodTemplate> methodList = new ArrayList<ApiMethodTemplate>();
                for (int n=0;n<classWrap.getMethodWraps().length;n++) {
                    MethodWrap methodWrap = classWrap.getMethodWraps()[n];
                    ApiMethodTemplate apiMethodTemplate = new ApiMethodTemplate();
                    apiMethodTemplate.setNo(n + 1);
                    apiMethodTemplate.setMethodName(methodWrap.getMethodName());
                    apiMethodTemplate.setMethodDefinition(methodWrap.toStatementNoModifiers());//方法定义,不要修饰符
                    apiMethodTemplate.setTitle(apiMethodTemplate.getMethodName());//标题
                    //返回值
                    if (methodWrap.getRtn() != null && !"void".equals(methodWrap.getRtn().getClassName())) {
                        Set<ClassWrap> set = selectBeans(methodWrap.getRtn(), new LinkedHashSet<ClassWrap>());
                        if (methodWrap.getRtnGenericWrap() != null) {//存在泛型,则查找泛型涉及的类
                            set = selectBeansFromGeneric(methodWrap.getRtnGenericWrap(), set);
                        }
                        //selectBeansFromGeneric(methodWrap.getRtnGenericWrap(), set);
                        List<ApiClassTemplate> list1 = new ArrayList<ApiClassTemplate>();
                        list1.add(new ApiClassTemplate(methodWrap.getRtn()));//返回结果类型
                        set.remove(methodWrap.getRtn());

                        List<ClassWrap> classWraps = new ArrayList<ClassWrap>(set);
                        for (int m=0;m<classWraps.size();m++) {
                            ClassWrap clz = classWraps.get(m);
                            if (clz == null) {
                                continue;
                            }
                            if (clz.isNormalClass()) {
                                //普通类型就不展示出来了
                                continue;
                            }
                            list1.add(new ApiClassTemplate(clz));
                        }
                        apiMethodTemplate.setRtnList(list1);
                    }

                    //入参
                    if (methodWrap.getParameterWraps() != null && methodWrap.getParameterWraps().length > 0) {
                        List<ApiClassTemplate> list2 = new ArrayList<ApiClassTemplate>();
                        for (int j=0;j<methodWrap.getParameterWraps().length;j++) {
                            ParameterWrap parameterWrap = methodWrap.getParameterWraps()[j];
                            Set<ClassWrap> set = selectBeans(parameterWrap.getClassWrap(), new LinkedHashSet<ClassWrap>());
                            if (parameterWrap.getGenericWrap() != null) {//存在泛型,则查找泛型涉及的类
                                set = selectBeansFromGeneric(parameterWrap.getGenericWrap(), set);
                            }
                            list2.add(new ApiClassTemplate(j + 1, parameterWrap.getClassWrap()));//入参声明的类带有序号
                            set.remove(parameterWrap.getClassWrap());
                            List<ClassWrap> classWraps = new ArrayList<ClassWrap>(set);
                            for (int m=0;m<classWraps.size();m++) {
                                ClassWrap clz = classWraps.get(m);
                                if (clz == null) {
                                    continue;
                                }
                                if (clz.isNormalClass()) {
                                    //普通类型就不展示出来了
                                    continue;
                                }
                                list2.add(new ApiClassTemplate(clz));
                            }
                        }
                        apiMethodTemplate.setParamList(list2);
                    }

                    methodList.add(apiMethodTemplate);//添加方法
                }
                apiTemplate.setMethodList(methodList);//设置方法详情

                res.add(apiTemplate);
            }

        }
        return res;
    }

    /**
     * 查找所有相关的bean
     * @param classWrap 指定类
     * @param set 已有的类
     * @return
     */

    public static Set<ClassWrap> selectBeans(ClassWrap classWrap, Set<ClassWrap> set){
        if (set.contains(classWrap)) {
            return set;
        }
        set.add(classWrap);//把当前的类加进去
        Set<ClassWrap> sub = new HashSet<ClassWrap>();
        if (classWrap.getFieldWraps() != null) {
            for (FieldWrap fieldWrap : classWrap.getFieldWraps()) {
                if (fieldWrap.getGenericWrap() != null) {//字段泛型收集,提到前面来,不然会导致丢掉部分类
                    //System.out.println(fieldWrap.getFieldName() + "--" + fieldWrap.getGenericWrap().getGenericChar() + "--" + sub.size());
                    selectBeansFromGeneric(fieldWrap.getGenericWrap(), sub);
                }
                if (fieldWrap.getClassWrap().isNormalClass()) {
                    continue;
                }
                if (set.contains(fieldWrap.getClassWrap())) {
                    continue;
                }
                sub.add(fieldWrap.getClassWrap());
            }
        }
        //set.addAll(sub);//把子类也放进来
        if (sub != null || sub.size() > 0) {
            //遍历子类,查询子类的子类
            for (ClassWrap classWrap1 : sub) {
                selectBeans(classWrap1, set);
            }
        }

        return set;
    }

    /**
     * 从泛型中查找bean
     * @param genericWrap
     * @param set
     * @return
     */
    public static Set<ClassWrap> selectBeansFromGeneric(GenericWrap genericWrap, Set<ClassWrap> set){
        if (genericWrap.getClassWrap() != null) {
            //set.add(genericWrap.getClassWrap());
            selectBeans(genericWrap.getClassWrap(), set);
        }
        if (genericWrap.getSub() != null && !genericWrap.getSub().isEmpty()) {
            for (GenericWrap sub : genericWrap.getSub()) {
                //遍历子泛型
                selectBeansFromGeneric(sub, set);
            }
        }
        return set;
    }
}
